Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

nice_things/macros/nice_build.macro.sh

These macros are not exactly part of the framework's public API. They are embedded directly in nice_build.sh, the template renderer used by the nice_things framework. Since these names are global, they are accessible in macro context at any time during the build process.

The functions documented in this page are not the only ones available during build. Almost all functions in the framework are imported globally in nice_build and can be invoked in macro context. The main exception are classes which are omitted, except for a few methods being used by the build system, like Array, Array_get, Array_length, Array_push; Map, Map_get, Map_set; PipeStatus, catch, try.

import

Since 0.3.0 · Source

Synopsis
import ["{ <name> [as <alias>], … }" from] <module>

Configuration

name=<package_name>
namespace=<package_namespace>

Description
Import functions and read-only variables from modules. Several modules can be imported in a single invocation, each with optional aliases for the names being imported.

Names being aliased by this function must have been published by the imported module using the public macro. Importing specific names can be omitted, in which case a module is imported just for its global names or side-effects.

Imported modules and each specific alias are rendered only once, on the first time they appear. Which means this macro may not print anything at the point of use if <module> has already been imported before as a dependency of another module.

The import function performs automatic namespace substitution on the imported modules. The namespace configuration property indicates the per-package namespace, and is optional. If omitted, it will fall back to using the package name as namespace. The name configuration property is itself also optional, falling back to using the directory name as package name.

Options

Operands

  • <name>: A public name to be aliased.
  • <alias>: An optional different alias to give <name> in this module's context.
  • <module>: A module specifier.

Stdin

Stdout
The imported modules are printed, each followed by its aliases if specified.

Stderr

Exit status

  • 0: Successful completion.
  • >0: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

#{{{
# Import a module only for it's side-effects without aliasing any names
import ./src/module.sh

# Import functions from a module to global scope
import "{ function1, function2 }" from ./src/module.sh

# Import readonly variable from a module to global scope
import "{ readonly:var_name }" from ./src/module.sh

# Import functions/readonly variables giving them namespaced aliases in the current module's scope
import "{
		readonly:var_name as NS__var_name,
		function1 as NS__function1,
		function2 as NS__function2
	}" from ./src/module.sh

# Import logging functions from nice_things to global scope
import \
	"{ abort }" from nice_things/log/abort.sh \
	"{ log_error, log_warn, log_info, log_debug, log_trace, log_is_level }" from nice_things/log/log.sh
#}}}

include

Since 0.3.0 · Source

Synopsis
include <module>…

Configuration

Description
Render a module once. Do nothing when trying to render the same <module> again.

Unlike the import macro, this function does not perform namespace substitution, and cannot alias names. It is most similar to the generic render macro, with the main difference being that it will not render the same <module> twice.

When importing source-code modules, you will almost always want to use the import macro instead. include and render are more appropriate for rendering other types of templates, usually with data instead of code, or code in another language instead of shell script.

Options

Operands
<module>: A module specifier.

Stdin

Stdout
The imported modules are printed.

Stderr

Exit status

  • 0: Successful completion.
  • >0: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

#{{{
# Render a template if not included yet
include ./src/file.template
#}}}

package_conf_get_bool

Since 0.3.0 · Source

Synopsis
package_conf_get_bool [-o | -r] <section> <property>

Configuration

Description
Read a boolean property from nice_package.conf.

The value of boolean properties must be true or false, otherwise the build is aborted with an error.

For a full explanation of all options and arguments, check the description of the package_conf_get_string macro.

Options

  • -o: Let the program configuration (./nice_package.conf), if present, override the configuration from the current package.
  • -r: Read the program configuration (./nice_package.conf) instead of the configuration for the current package. Note that this mode will abort if the configuration file does not exist.

Operands

  • <section>: Name of the section, including the square brackets.
  • <property>: Name of the property.

Stdin

Stdout

Stderr

Exit status

  • 0: Property is true.
  • 1: Property is false.
  • >1: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

NS__no_color=#{{{
# If config property is set to true, set this variable
if package_conf_get_bool module no_color; then
	printf 1
fi
#}}}

package_conf_get_string

Since 0.3.0 · Source

Synopsis
package_conf_get_string [-o | -r] <out_var> <section> <property>

Configuration

Description
Read a string property from nice_package.conf.

By default this macro reads the configuration file for the package the current module is part of. That is, the configuration for the module where it is invoked. The option flags -o and -r can be used to change that behavior, letting the configuration for the program being built override the module configuration, or reading only the program configuration, respectively.

Besides the name of a section in the configuration file, the <section> argument also accepts two special literal values:

  • module: A dynamic section named after the module identifier of the form [module:path/to/module.sh].
  • package: A dynamic section named after the package of the form [package:package_name].

When using the dynamic sections, the options -o and -r are ignored, they always behave as if the -o option is set.

The dynamic section format is the recommended way to configure public modules in library packages. They allow configuration either at the package or at the module level and protect against name collisions. Here is an example configuration from the nice_things framework:

[package:nice_things]
# Value to be assigned to the IFS variable in strict_mode; accepts printf-style escape sequences
strict_mode_ifs=\037

[module:nice_things/log/log.sh]
# If true, info logs will be preceded by their level name (INFO), like the other levels
named_info=false
# If true, runtime config will default to 'no-color'
no_color=false
# Name of the variable used for runtime configuration
variable=LOG_LEVEL

In framework code those can be read as:

#{{{
# Read package configuration
# Note how `package` must be explicitly set for this to work in public modules
package=nice_things package_conf_get_string out_var package strict_mode_ifs
#}}}

#{{{
# Read configuration specific to the current module
package_conf_get_string out_var module variable
#}}}

Options

  • -o: Let the program configuration (./nice_package.conf), if present, override the configuration from the current package.
  • -r: Read the program configuration (./nice_package.conf) instead of the configuration for the current package.

Operands

  • <out_var>: Output variable; the result will be written to this variable.
  • <section>: Name of the section, including the square brackets.
  • <property>: Name of the property.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • 1: <property> not found.
  • >1: Unexpected error (abort).
  • 21: Invalid property value in config file. Expected string but found array.

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

NS__param_level=${1:-"{{{" package_conf_get_string value module variable && printf '${%s-}' "$value" "}}}"}

package_conf_print_string

Since 0.3.0 · Source

Synopsis
package_conf_print_string [-o | -r] <section> <property>

Configuration

Description
Print the value of a string property from nice_package.conf.

For a full explanation of all options and arguments, check the description of the package_conf_get_string macro.

Options

  • -o: Let the program configuration (./nice_package.conf), if present, override the configuration from the current package.
  • -r: Read the program configuration (./nice_package.conf) instead of the configuration for the current package.

Operands

  • <section>: Name of the section, including the square brackets.
  • <property>: Name of the property.

Stdin

Stdout
The value of the property is printed.

Stderr

Exit status

  • 0: Successful completion.
  • 1: <property> not found.
  • >1: Unexpected error (abort).
  • 21: Invalid property value in config file. Expected string but found array.

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

# Print the module specifier and package version for the current module
# {{{$module}}} {{{ package_conf_print_string "[]" version }}}

package_get

Since 0.3.0 · Source

Synopsis
package_get <package> [<out_var> <property>]…

Configuration

Description
Read package properties.

The list of properties a package has are:

  • name: Name of the package; the value of the name property in nice_package.conf if specified, or fall back to dir_name (this function retrieves a package by name, so this property is redundant).
  • namespace: The package namespace; the value of the namespace property in nice_package.conf if specified, or fall back to the name of the package.
  • dir_name: The name of the root directory of the package.
  • path: Relative path to the root directory of the package.
  • config_file: Relative path to the package's configuration file nice_package.conf, if it exists; null otherwise.
  • config: A reference to the package's Config object, if it exists; null otherwise.

Note

This function was made for internal use in nice_build. Many other macros exist to read a package's configuration, so look at them first: package_conf_get_bool, package_conf_get_string, package_conf_print_string.
It is unlikely that application code will need to access a package's data directly using this macro.

Options

Operands

  • <package>: Name of package.
  • <out_var>: Output variable; the result will be written to this variable.
  • <property>: Property to retrieve.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • 1: One or more <property> does not exist in the package.
  • 3: <package> not found.

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

#{{{
package_get "$package" package_path path || exit
log_debug "The package '${package}' is at path '${package_path}'"
#}}}

public

Since 0.3.0 · Source

Synopsis
public [readonly:]<name>…

Configuration

Description
Publish a <name> from the current module.

A <name> can be a namespaced function (NS__function_name) or read-only variable (readonly NS__var_name), by prepending the readonly: prefix to the public declaration. Names must be public to be imported by dependent modules with the import macro.

Warning

The public declaration should always be the first macro at the top of a module. To prevent errors on circular dependencies, the import macro must always come after the public declaration.

Note that the complete names are used in the public declaration including their namespaces, but the modules importing them omit the namespace as that is automatically added by the import macro. Only namespace'd names can be declared public; there is no reason to publish non-namespace'd names as they are already global.

Names ending in an underscore character (_) are private and cannot be published. Use this mechanism to explicitly mark private names to prevent accidentally leaking them on the public interface.

Options

Operands
<name>: A namespaced function or read-only variable in the current module.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • >0: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

#{{{
public \
	readonly:NS__var_name \
	NS__some_function \
	NS__another_function
#}}}

render

Since 0.3.0 · Source

Synopsis
render [<module>…]

Configuration

Description
Render a template to stdout. Templates are read from <module> arguments. If no arguments are provided, the template is read from stdin.

For details on the template format, refer to the documentation of the template engine at https://codeberg.org/nice_things/template.sh

Note

If you want to print the contents of a file but do not need to render it as a template, you can simply call the cat function in macro context.

Options

Operands
<module>: A module specifier.

Stdin
Only read if no arguments are provided.

Stdout
The rendered template is printed.

Stderr

Exit status

  • 0: Successful completion.
  • >0: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

#{{{
# Render a template in the current position
render ./src/file.template
#}}}

use_macro

Since 0.3.0 · Source

Synopsis
use_macro <macro>…

Configuration

Description
Execute macros in the current context.

Application macros are automatically executed from the file at ./src/main.macro.sh, and macros from the nice_things framework are also executed automatically. If another dependency provides public macros for application use, you will have to execute them manually using this function. Normally you will invoke the use_macro function in the application's ./src/main.macro.sh file to load macros before rendering starts.

Options

Operands
<macro>: A module specifier pointing to a macro file.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • >0: Unexpected error (abort).

Abort
Any failure will abort the build process. No runtime abort is added.

Usage examples

use_macro package/path/to/file.macro.sh

readonly:module

Since 0.3.0 · Source

Synopsis
{{{$module}}}

Configuration

Description
Module identifier of the current module.

Options

Operands

Stdin

Stdout

Stderr

Exit status

Abort

Usage examples

# Module: {{{$module}}}

readonly:module_path

Since 0.3.0 · Source

Synopsis
{{{$module_path}}}

Configuration

Description
Relative path to the current module.

Options

Operands

Stdin

Stdout

Stderr

Exit status

Abort

Usage examples

# Module path: {{{$module_path}}}

readonly:ns

Since 0.3.0 · Source

Synopsis
{{{$ns}}}

Configuration

Description
Namespace of the current module.

Options

Operands

Stdin

Stdout

Stderr

Exit status

Abort

Usage examples

# Module namespace: {{{$ns}}}

readonly:package

Since 0.3.0 · Source

Synopsis
{{{$package}}}

Configuration

Description
Name of the package the current module belongs to.

Options

Operands

Stdin

Stdout

Stderr

Exit status

Abort

Usage examples

# Package: {{{$package}}}

readonly:root_package

Since 0.3.0 · Source

Synopsis
{{{$root_package}}}

Configuration

Description
Name of the root package. This is the program being built.

Options

Operands

Stdin

Stdout

Stderr

Exit status

Abort

Usage examples

# Program: {{{$root_package}}}